package com.huaguoguo.cyg.spider.parse;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.impl.NumberConverter;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.huaguoguo.cyg.converter.StringActionDataConverter;
import com.huaguoguo.cyg.converter.UrlParamConverter;
import com.huaguoguo.cyg.entity.weibo.to.WBDetail;
import com.huaguoguo.cyg.entity.weibo.to.WBFrom;
import com.huaguoguo.cyg.entity.weibo.to.WBHandle;
import com.huaguoguo.cyg.entity.weibo.to.WBMediaWrap;
import com.huaguoguo.cyg.exceptions.SpiderParseException;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import us.codecraft.xsoup.Xsoup;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * /**
 * 类说明： 博客解析器<br/>
 * author:huaguoguo
 * Date: 2020/2/1
 * Time: 13:50
 */
@Slf4j
public class WBDetailParser {

    public static List<WBDetail> parseHtmlToWBDetail(Document content) {
        // 5. 开始解析
        Elements minfos = Xsoup.compile("//div[@tbinfo]").evaluate(content).getElements();
        return minfos.stream()
                .map(m -> {
                    try {
                        return WBDetailParser.parseWBDetail(m);
                    } catch (Exception e) {
                        log.error("当前博客解析失败", e);
                        return null;
                    }
                })
                .filter(m -> m != null)
                .collect(Collectors.toList());
    }

    /**
     * 解析整条微博
     *
     * @param minfo
     * @return
     */
    public static WBDetail parseWBDetail(Element minfo) {
        WBDetail.WBDetailBuilder wbDetailBuilder = WBDetail.builder();
        // 解析mid
        String mid = WBDetailParser.parseMid(minfo);
        // 解析不到mid跳过当前循环
        if (StrUtil.isEmpty(mid)) {
            throw new SpiderParseException("解析不到mid");
        }
        wbDetailBuilder.mid(mid);
        // 解析博客的from
        wbDetailBuilder.wbFrom(WBDetailParser.parseWBFrom(minfo));
        // 解析博客的文本内容
        wbDetailBuilder.wbText(WBDetailParser.parseWBText(minfo));
        // 解析多媒体内容 图片，视频等
        WBMediaWrap wbMediaWrap = WBDetailParser.parseWBMediaWrap(minfo);
        if (wbMediaWrap != null) {
            wbDetailBuilder.wbMediaWrap(wbMediaWrap);
        }
        // 解析 WB_handle： 转发、评论、点赞数量
        wbDetailBuilder.wbHandle(WBDetailParser.parseWBHandle(minfo));
        // 解析转发内容
        Element wbFeedExpandElement = Xsoup.compile("//div[@class='WB_feed_expand']").evaluate(minfo).getElements().first();
        if (wbFeedExpandElement != null) {
            wbDetailBuilder.wbFeedExpand(WBDetailParser.parseWBDetail(wbFeedExpandElement));
        }
        return wbDetailBuilder.build();
    }

    /**
     * 原创博客的mid在 a标签的name属性中 <br>
     * 转发博客的mid在 a标签的 suda-uatrack 中，如下:<br>
     * suda-uatrack = "key=tblog_home_new&value=feed_time:4467525968448079:fromprofile" <br>
     * key=feed_trans_weibo&value=time:4465977209077007:fromprofile <br>
     * 解析到当前博客的mid
     *
     * @param minfo
     * @return
     */
    public static String parseMid(Element minfo) {
        // 1. 先从a标签的name中取
        List<String> mid = Xsoup.compile("//div[contains(@class, 'WB_from')]/a[@name]/@name").evaluate(minfo).list();
        // 2. 没有name再从 suda-uatrack 取
        if (mid.size() == 0) {
            mid = Xsoup.compile("//div[contains(@class, 'WB_from')]/a[@suda-uatrack]/@suda-uatrack").evaluate(minfo).list();
            if (mid.size() == 0) {
                throw new SpiderParseException("解析不到mid");
            }
            Map<String, Object> map = new UrlParamConverter().convert(mid.get(0), null);
            String value = MapUtil.getStr(map, "value");
            return value.split(":")[1];
        }
        return mid.get(0);
    }

    /**
     * 解析博客的from
     *
     * @return
     */
    public static WBFrom parseWBFrom(Element minfo) {
        WBFrom.WBFromBuilder builder = WBFrom.builder();
        // 0是博客时间  1是转发的时间
        List<String> titles = Xsoup.compile("//div[contains(@class, 'WB_from')]/a[@title]/@title").evaluate(minfo).list();
        LocalDateTime dateTime = LocalDateTime.parse(titles.get(0), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
        builder.fromDateTime(dateTime);
        // 0,1是博客时间和来源  2,3是转发的时间和来源   1月17日 09:34
        List<String> fromList = Xsoup.compile("//div[contains(@class, 'WB_from')]/a/text()").evaluate(minfo).list();
        // 有的博客可能没有转发来源，不判断会抛出数组越界异常
        if (CollUtil.isNotEmpty(fromList) && fromList.size() > 1) {
            builder.fromEndPoint(fromList.get(1));
        }
        return builder.build();
    }

    /**
     * 解析出博客文本内容
     *
     * @param minfo
     * @return
     */
    public static String parseWBText(Element minfo) {
        List<String> list = Xsoup.compile("//div[contains(@class, 'WB_text')]/text()").evaluate(minfo).list();
        return list.get(0);
    }

    /**
     * 解析多媒体内容 <br>
     * 一条博客中WBMediaWrap只有一个 <br>
     *
     * @param minfo
     * @return
     */
    public static WBMediaWrap parseWBMediaWrap(Element minfo) {
        // 如果是minfo，return null ， 递归进入转发div，再解析
        // 判断是minfo
        if (StrUtil.isNotEmpty(minfo.attr("minfo"))) {
            return null;
        }
        // 上面的校验能过说明是原创了
        // 如果是tbinfo， 直接解析
        List<String> list = Xsoup.compile("//ul[contains(@class, 'WB_media_a')]/@action-data").evaluate(minfo).list();
        // 获取所有图片的url
        // div[contains(@class, 'demo') and contains(@class, 'other')] WB_media_a WB_media_a_mn
        // 解析成java对象格式  Xsoup.compile("//div[@minfo]").evaluate(content).list()
        Optional<WBMediaWrap> wbMediaWrap = list.stream()
                .filter(StrUtil::isNotEmpty)
                .map(item -> new StringActionDataConverter().convert(item, null))
                .filter(item -> item != null)
                .findFirst();
        return wbMediaWrap.orElse(null);
    }

    /**
     * //*[@id="Pl_Official_MyProfileFeed__20"]/div/div[3]/div[1]/div[3]/div[5]/div[2]/div[5]/div[1]/ul
     * 解析 WB_handle： 转发、评论、点赞数量
     *
     * @param minfo
     * @return
     */
    public static WBHandle parseWBHandle(Element minfo) {
        WBHandle.WBHandleBuilder builder = WBHandle.builder();
        builder.forward(getWBHandleCount("forward_btn_text", minfo))
                .comment(getWBHandleCount("comment_btn_text", minfo))
                .like(getWBHandleCount("like_status", minfo));
        return builder.build();
    }

    /**
     * 获取转发、评论、点赞数量公用解析方法
     * Xsoup.compile("//div[@class='WB_handle']//li[1]//em/text()").evaluate(minfo)
     *
     * @param nodeType
     * @param minfo
     * @return
     */
    private static Integer getWBHandleCount(String nodeType, Element minfo) {
        String xpathStr =
                StrUtil.format("//div[@class='WB_handle']/ul[@class='WB_row_line']//span[@class='pos']//span[@node-type='{}']//em/text()", nodeType);
        List<String> list = Xsoup.compile(xpathStr).evaluate(minfo).list();
        // 转发的用上面的xpath解析不到，用if里的解析
        if (list.size() == 0) {
            return getMInfoWBHandleCount(nodeType, minfo);
        }
        return new NumberConverter().convertQuietly(CollUtil.getLast(list), 0).intValue();
    }

    /**
     * 解析转发博客中的 转发，评论，点赞数量
     * @param nodeType
     * @param minfo
     * @return
     */
    private static Integer getMInfoWBHandleCount(String nodeType, Element minfo) {
        String xpathTemp = "//div[@class='WB_handle']//li[{}]//em/text()";
        String xpathStr = null;
        switch (nodeType) {
            case "forward_btn_text":
                xpathStr = StrUtil.format(xpathTemp, 1);
                break;
            case "comment_btn_text":
                xpathStr = StrUtil.format(xpathTemp, 2);
                break;
            case "like_status" :
                xpathStr = StrUtil.format(xpathTemp, 3);
                break;
            default:
                return 0;
        }
        List<String> list = Xsoup.compile(xpathStr).evaluate(minfo).list();
        if (list.size() == 0) {
            return 0;
        }
        return new NumberConverter().convertQuietly(CollUtil.getLast(list), 0).intValue();
    }
}
